home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / guspeak.zip / PARSE.C < prev    next >
C/C++ Source or Header  |  1993-06-29  |  13KB  |  619 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <gf1proto.h>
  6. #include <ultraerr.h>
  7. #include <dos.h>
  8. #define MAX_LENGTH 128
  9.  
  10. static FILE *In_file;
  11. static FILE *Out_file;
  12. static int no_ultra = 0;
  13. static int Char, Char1, Char2, Char3;
  14. static void load_phonemes(void);
  15.  
  16. int makeupper(int character);
  17. int new_char(void);
  18. void xlate_file(void);
  19. void have_dollars(void);
  20. void have_special(void );
  21. void have_number(void);
  22. void have_letter(void);
  23. void abbrev(char buff[]);
  24. void outstring(char *string);
  25. void say_ordinal(long int value);
  26. void say_cardinal(long int value);
  27. void say_ascii(int character);
  28. void spell_word(char *word);
  29. void xlate_word(char *buf);
  30. void outchar(int chr);
  31. /*
  32. ** main(argc, argv)
  33. **    int argc;
  34. **    char *argv[];
  35. **
  36. **    This is the main program.  It takes up to two file names (input
  37. **    and output)  and translates the input file to phoneme codes
  38. **    (see ENGLISH.C) on the output file.
  39. */
  40. int verbose = 0;
  41. int debug = 0;
  42. void main(int argc, char *argv[])
  43. {
  44.     int i=1;
  45.  
  46.     /* process switches */
  47.     while (argv[i][0] == '-') {
  48.         switch (argv[i++][1]) {
  49.             case 'd': debug = 1; break;
  50.             case 'v': verbose = 1; break;
  51.             default :
  52.                 fputs("Usage: PHONEME [-v -d] [infile [outfile]]\n", stderr);
  53.                 fputs(" -v  verbose mode (print phonemes)\n", stderr);
  54.                 fputs(" -d  debug mode speak each phoneme\n", stderr);
  55.                 exit(0);
  56.         }
  57.     }
  58.     --i;
  59.     if ((argc-i) > 1)
  60.         {
  61.         In_file = fopen(argv[1+i], "r");
  62.         if (In_file == 0)
  63.             {
  64.             fputs("Error: Cannot open input file.\n", stderr);
  65.             fputs("Usage: PHONEME [infile [outfile]]\n", stderr);
  66.             exit(0);
  67.             }
  68.         }
  69.     else
  70.         In_file = stdin;
  71.  
  72.     if (argc-i > 2)
  73.         {
  74.         Out_file = fopen(argv[2+i], "w");
  75.         if (Out_file == 0)
  76.             {
  77.             fputs("Error: Cannot create output file.\n", stderr);
  78.             fputs("Usage: PHONEME [-d-v] [infile [outfile]]\n", stderr);
  79.             exit(0);
  80.             }
  81.         }
  82.     else
  83.         Out_file = stdout;
  84.  
  85.     load_phonemes();
  86.     if (argc-i == 1)    {
  87.         fputs("Enter english text:\n", stderr);
  88.     }
  89.     xlate_file();
  90.     UltraClose();
  91. }
  92. /* an array of all phonemes */
  93. static char *phoneme_name[] = {
  94.     "IY",    "EY",    "AE",    "AO",    "UH",
  95.     "ER",    "AH",    "AW",    "IH",    "EH",
  96.     "AA",    "OW",    "UW",    "AX",    "AY",
  97.     "OY",    "YU",    "p",    "t",    "k",
  98.     "f",    "TH",    "s",    "SH",    "HH",
  99.     "n",    "l",    "y",    "CH",    "WH",
  100.     "b",    "d",    "g",    "v",    "DH",
  101.     "z",    "ZH",    "m",    "NG",    "w",
  102.     "r",    "j"
  103. };
  104. /* this stucture holds that gravis start and end address for each phoneme */
  105. /* phonemes that start with upperchase char are two characters long */
  106. static struct w_table {
  107.         unsigned long start;
  108.         unsigned long end;
  109. } p_tab[sizeof(phoneme_name)/sizeof(char *)];
  110.  
  111.  
  112. /* return index of phonemes s in phoneme_name array.
  113. ** return -1 if not found
  114. */
  115. int find_phon_index(char *s)
  116. {
  117.     int len;
  118.     int i;
  119.  
  120.     /* if two character search */
  121.     if (isupper(*s))
  122.         len = 2;
  123.     else
  124.         len = 1;
  125.     for (i = 0;i < sizeof(phoneme_name)/sizeof(char *); i++) {
  126.         if (strncmp(s,phoneme_name[i], len) == 0)
  127.             return(i);
  128.     }
  129.     return(-1);
  130.  
  131. }
  132.  
  133. /* break the string s up into sound samples and play them */
  134. void gus_speak(char *s)
  135. {
  136.     int i;
  137.     char *p = s;
  138.  
  139.     /* while there are phonemes */
  140.     while(*p) {
  141.  
  142.         /* if pause then wait .1 sec */
  143.         if (*p == ' ') {
  144.             delay(100);
  145.             /* bump pointer to start of next phoneme */
  146.             p++;
  147.             continue;
  148.         }
  149.         i = find_phon_index(p);
  150.         if (i < 0) {
  151.             printf("\n[%s] phoneme not found in voice table ", p);
  152.             p++;
  153.             continue;
  154.         }
  155.         /* play the phoneme sound sound */
  156.         UltraStartVoice(1, p_tab[i].start, p_tab[i].start, p_tab[i].end, 4);
  157.  
  158.         /* wait for sound to stop */
  159.         while(!UltraVoiceStopped(1));
  160.  
  161.         /* bumb pointer to start of next phoneme */
  162.         if isupper(*(p++))
  163.             p++;
  164.     }
  165. }
  166.  
  167. void outstring(char *string)
  168. {
  169.  
  170.     /* if ultrasound is instaled then speak the string */
  171.     if (!no_ultra)
  172.         gus_speak(string);
  173.  
  174.     if (!verbose)
  175.         return;
  176.     /* print the string */
  177.     while (*string != '\0')
  178.         outchar(*string++);
  179. }
  180.  
  181. void outchar(int chr)
  182. {
  183.     fputc(chr,Out_file);
  184. }
  185.  
  186.  
  187. int makeupper(int character)
  188. {
  189.     if (islower(character))
  190.         return toupper(character);
  191.     else
  192.         return character;
  193. }
  194.  
  195. int new_char(void)
  196. {
  197.     /*
  198.     If the cache is full of newline, time to prime the look-ahead
  199.     again.  If an EOF is found, fill the remainder of the queue with
  200.     EOF's.
  201.     */
  202.     if (Char == '\n'  && Char1 == '\n' && Char2 == '\n' && Char3 == '\n')
  203.         {    /* prime the pump again */
  204.         Char = getc(In_file);
  205.         if (Char == EOF)
  206.             {
  207.             Char1 = EOF;
  208.             Char2 = EOF;
  209.             Char3 = EOF;
  210.             return Char;
  211.             }
  212.         if (Char == '\n')
  213.             return Char;
  214.  
  215.         Char1 = getc(In_file);
  216.         if (Char1 == EOF)
  217.             {
  218.             Char2 = EOF;
  219.             Char3 = EOF;
  220.             return Char;
  221.             }
  222.         if (Char1 == '\n')
  223.             return Char;
  224.  
  225.         Char2 = getc(In_file);
  226.         if (Char2 == EOF)
  227.             {
  228.             Char3 = EOF;
  229.             return Char;
  230.             }
  231.         if (Char2 == '\n')
  232.             return Char;
  233.  
  234.         Char3 = getc(In_file);
  235.         }
  236.     else
  237.         {
  238.         /*
  239.         Buffer not full of newline, shuffle the characters and
  240.         either get a new one or propagate a newline or EOF.
  241.         */
  242.         Char = Char1;
  243.         Char1 = Char2;
  244.         Char2 = Char3;
  245.         if (Char3 != '\n' && Char3 != EOF)
  246.             Char3 = getc(In_file);
  247.         }
  248.     return Char;
  249.     }
  250.  
  251. /*
  252. ** xlate_file()
  253. **
  254. **    This is the input file translator.  It sets up the first character
  255. **    and uses it to determine what kind of text follows.
  256. */
  257. void xlate_file(void)
  258. {
  259.     /* Prime the queue */
  260.     Char = '\n';
  261.     Char1 = '\n';
  262.     Char2 = '\n';
  263.     Char3 = '\n';
  264.     new_char();    /* Fill Char, Char1, Char2 and Char3 */
  265.  
  266.     while (Char != EOF)    /* All of the words in the file */
  267.         {
  268.         if (isdigit(Char))
  269.             have_number();
  270.         else
  271.         if (isalpha(Char) || Char == '\'')
  272.             have_letter();
  273.         else
  274.         if (Char == '$' && isdigit(Char1))
  275.             have_dollars();
  276.         else
  277.             have_special();
  278.         }
  279.     }
  280.  
  281. void have_dollars(void)
  282. {
  283.     long int value;
  284.  
  285.     value = 0L;
  286.     for (new_char() ; isdigit(Char) || Char == ',' ; new_char())
  287.         {
  288.         if (Char != ',')
  289.             value = 10 * value + (Char-'0');
  290.         }
  291.  
  292.     say_cardinal(value);    /* Say number of whole dollars */
  293.  
  294.     /* Found a character that is a non-digit and non-comma */
  295.  
  296.     /* Check for no decimal or no cents digits */
  297.     if (Char != '.' || !isdigit(Char1))
  298.         {
  299.         if (value == 1L)
  300.             outstring("dAAlER ");
  301.         else
  302.             outstring("dAAlAArz ");
  303.         return;
  304.         }
  305.  
  306.     /* We have '.' followed by a digit */
  307.  
  308.     new_char();    /* Skip the period */
  309.  
  310.     /* If it is ".dd " say as " DOLLARS AND n CENTS " */
  311.     if (isdigit(Char1) && !isdigit(Char2))
  312.         {
  313.         if (value == 1L)
  314.             outstring("dAAlER ");
  315.         else
  316.             outstring("dAAlAArz ");
  317.         if (Char == '0' && Char1 == '0')
  318.             {
  319.             new_char();    /* Skip tens digit */
  320.             new_char();    /* Skip units digit */
  321.             return;
  322.             }
  323.  
  324.         outstring("AAnd ");
  325.         value = (Char-'0')*10 + Char1-'0';
  326.         say_cardinal(value);
  327.  
  328.         if (value == 1L)
  329.             outstring("sEHnt ");
  330.         else
  331.             outstring("sEHnts ");
  332.         new_char();    /* Used Char (tens digit) */
  333.         new_char();    /* Used Char1 (units digit) */
  334.         return;
  335.         }
  336.  
  337.     /* Otherwise say as "n POINT ddd DOLLARS " */
  338.  
  339.     outstring("pOYnt ");
  340.     for ( ; isdigit(Char) ; new_char())
  341.         {
  342.         say_ascii(Char);
  343.         }
  344.  
  345.     outstring("dAAlAArz ");
  346.  
  347.     return;
  348. }
  349.  
  350. void have_special(void )
  351.     {
  352.     if (Char == '\n')
  353.         outchar('\n');
  354.     else
  355.     if (!isspace(Char))
  356.         say_ascii(Char);
  357.  
  358.     new_char();
  359.     return;
  360. }
  361.  
  362.  
  363. void have_number(void)
  364. {
  365.     long int value;
  366.     int lastdigit;
  367.  
  368.     value = Char - '0';
  369.     lastdigit = Char;
  370.  
  371.     for (new_char() ; isdigit(Char) ; new_char())
  372.         {
  373.         value = 10 * value + (Char-'0');
  374.         lastdigit = Char;
  375.         }
  376.  
  377.     /* Recognize ordinals based on last digit of number */
  378.     switch (lastdigit)
  379.         {
  380.     case '1':    /* ST */
  381.         if (makeupper(Char) == 'S' && makeupper(Char1) == 'T' &&
  382.             !isalpha(Char2) && !isdigit(Char2))
  383.             {
  384.             say_ordinal(value);
  385.             new_char();    /* Used Char */
  386.             new_char();    /* Used Char1 */
  387.             return;
  388.             }
  389.         break;
  390.  
  391.     case '2':    /* ND */
  392.         if (makeupper(Char) == 'N' && makeupper(Char1) == 'D' &&
  393.             !isalpha(Char2) && !isdigit(Char2))
  394.             {
  395.             say_ordinal(value);
  396.             new_char();    /* Used Char */
  397.             new_char();    /* Used Char1 */
  398.             return;
  399.             }
  400.         break;
  401.  
  402.     case '3':    /* RD */
  403.         if (makeupper(Char) == 'R' && makeupper(Char1) == 'D' &&
  404.             !isalpha(Char2) && !isdigit(Char2))
  405.             {
  406.             say_ordinal(value);
  407.             new_char();    /* Used Char */
  408.             new_char();    /* Used Char1 */
  409.             return;
  410.             }
  411.         break;
  412.  
  413.     case '0':    /* TH */
  414.     case '4':    /* TH */
  415.     case '5':    /* TH */
  416.     case '6':    /* TH */
  417.     case '7':    /* TH */
  418.     case '8':    /* TH */
  419.     case '9':    /* TH */
  420.         if (makeupper(Char) == 'T' && makeupper(Char1) == 'H' &&
  421.             !isalpha(Char2) && !isdigit(Char2))
  422.             {
  423.             say_ordinal(value);
  424.             new_char();    /* Used Char */
  425.             new_char();    /* Used Char1 */
  426.             return;
  427.             }
  428.         break;
  429.         }
  430.  
  431.     say_cardinal(value);
  432.  
  433.     /* Recognize decimal points */
  434.     if (Char == '.' && isdigit(Char1))
  435.         {
  436.         outstring("pOYnt ");
  437.         for (new_char() ; isdigit(Char) ; new_char())
  438.             {
  439.             say_ascii(Char);
  440.             }
  441.         }
  442.  
  443.     /* Spell out trailing abbreviations */
  444.     if (isalpha(Char))
  445.         {
  446.         while (isalpha(Char))
  447.             {
  448.             say_ascii(Char);
  449.             new_char();
  450.             }
  451.         }
  452.  
  453.     return;
  454. }
  455.  
  456.  
  457. void have_letter(void)
  458. {
  459.     char buff[MAX_LENGTH];
  460.     int count;
  461.  
  462.     count = 0;
  463.     buff[count++] = ' ';    /* Required initial blank */
  464.  
  465.     buff[count++] = makeupper(Char);
  466.  
  467.     for (new_char() ; isalpha(Char) || Char == '\'' ; new_char())
  468.         {
  469.         buff[count++] = makeupper(Char);
  470.         if (count > MAX_LENGTH-2)
  471.             {
  472.             buff[count++] = ' ';
  473.             buff[count++] = '\0';
  474.             xlate_word(buff);
  475.             count = 1;
  476.             }
  477.         }
  478.  
  479.     buff[count++] = ' ';    /* Required terminating blank */
  480.     buff[count++] = '\0';
  481.  
  482.     /* Check for AAANNN type abbreviations */
  483.     if (isdigit(Char))
  484.         {
  485.         spell_word(buff);
  486.         return;
  487.         }
  488.     else
  489.     if (strlen(buff) == 3)     /* one character, two spaces */
  490.         say_ascii(buff[1]);
  491.     else
  492.     if (Char == '.')        /* Possible abbreviation */
  493.         abbrev(buff);
  494.     else
  495.         xlate_word(buff);
  496.  
  497.     if (Char == '-' && isalpha(Char1))
  498.         new_char();    /* Skip hyphens */
  499.  
  500. }
  501.  
  502. /* Handle abbreviations.  Text in buff was followed by '.' */
  503. void abbrev(char buff[])
  504. {
  505.     if (strcmp(buff, " DR ") == 0)
  506.         {
  507.         xlate_word(" DOCTOR ");
  508.         new_char();
  509.         }
  510.     else
  511.     if (strcmp(buff, " MR ") == 0)
  512.         {
  513.         xlate_word(" MISTER ");
  514.         new_char();
  515.         }
  516.     else
  517.     if (strcmp(buff, " MRS ") == 0)
  518.         {
  519.         xlate_word(" MISSUS ");
  520.         new_char();
  521.         }
  522.     else
  523.     if (strcmp(buff, " PHD ") == 0)
  524.         {
  525.         spell_word(" PHD ");
  526.         new_char();
  527.         }
  528.     else
  529.         xlate_word(buff);
  530. }
  531.  
  532. static ULTRA_CFG config;
  533. /* load phoneme sounds into gravis board */
  534. static void load_phonemes(void)
  535. {
  536.     int i = 0;
  537.     long silence;
  538.     int j = 0;
  539.     int ndx;
  540.     FILE *fp;
  541.     char name[80];
  542.     long size;
  543.     int *buf;
  544.     int *p;
  545.     int len;
  546.     unsigned char tmp1=0;
  547.     unsigned char tmp2=0;
  548.  
  549.     UltraGetCfg(&config);
  550.     if (UltraOpen(&config,14) != ULTRA_OK) {
  551.         no_ultra = 1;
  552.         printf("\nNo Ultrasound card found.  Sound will not be used");
  553.         return;
  554.     }
  555.     /* Reset ultrasound */
  556.     UltraReset(14);
  557.     UltraDisableOutput();
  558.     UltraSetLinearVolume(1,510);
  559.     UltraSetBalance(1, 7);
  560.  
  561.     /* send a zero sample to the gus so that unused voices can use it */
  562.     UltraMemAlloc(2, &silence);
  563.     UltraDownload(&j, 0x40, silence, 2, 1);
  564.  
  565.     /* set all voices to silence area of storage */
  566.     for (i = 0 ; i < 14; i++)
  567.         UltraSetVoice(i, silence);
  568.     UltraEnableOutput();
  569.     UltraSetFrequency(1, 9000L);
  570.     UltraMemInit();
  571.  
  572.     printf("\nLoading ultrasound...\n");
  573.     for (ndx = 0; ndx < sizeof(phoneme_name)/sizeof(char *); ndx++) {
  574.         strcpy(name, phoneme_name[ndx]);
  575.         strcat(name, ".sam");
  576.         if ((fp = fopen(name, "rb")) == NULL) {
  577.             printf("\ncan't open phoneme file %s",name);
  578.             continue;
  579.         }
  580.         /* find each file and its size*/
  581.         fseek(fp, 0L, SEEK_END);
  582.         size = ftell(fp);
  583.         fseek(fp, 0, SEEK_SET);
  584.         buf = (int *)malloc(size);
  585.         if (buf == NULL) {
  586.             printf("\nCan't malloc buffer for %s file",name);
  587.             return;
  588.         }
  589.  
  590.         for (p = buf, i = 0; i < size; i += 2, p++) {
  591.             fread(p, 2,1 ,fp);
  592.         }
  593.  
  594.         /* allocate gus space for phoneme */
  595.         i = UltraMemAlloc(size, &p_tab[ndx].start);
  596.         p_tab[ndx].end = p_tab[ndx].start + size;
  597.         if (i == NO_MEMORY) {
  598.             printf("\nGus out of memory for phoneme storage at %s", name);
  599.         }
  600.         else {
  601.             UltraDownload(buf, 0x40, p_tab[ndx].start, size, 1);
  602.         }
  603.  
  604.         fclose(fp);
  605.         free(buf);
  606.     }
  607.  
  608.     if (debug ) {
  609.         for (i = 0; i < sizeof(phoneme_name)/sizeof(char *); i++) {
  610.             printf("\n%s", phoneme_name[i]);
  611.             UltraStartVoice(1, p_tab[i].start, p_tab[i].start,    p_tab[i].end,
  612.                 4);
  613.             while(!UltraVoiceStopped(1));
  614.             delay(300);
  615.         }
  616.         printf("\n");
  617.     }
  618. }
  619.